<?php

namespace helper;


class Tree
{

  /**
   * 返回多层栏目
   * @param array|object $data 操作的数组
   * @param int $pid 一级PID的值
   * @param string $node
   * @param string $html 栏目名称前缀
   * @param string $fieldPri 唯一键名，如果是表则是表的主键
   * @param string $fieldPid 父ID键名
   * @param int $level 不需要传参数（执行时调用）
   * @return array
   */
  static public function channelLevel($data, $pid = 0, $node = "children", $html = "&nbsp;", $fieldPri = 'id', $fieldPid = 'pid', $level = 1)
  {
    if (empty($data)) {
      return array();
    }
    $arr = array();
    foreach ($data as $v) {
      if ($v[$fieldPid] == $pid) {
        $arr[$v[$fieldPri]]           = $v;
        $arr[$v[$fieldPri]]['_level'] = $level;
        $arr[$v[$fieldPri]]['_html']  = str_repeat($html, $level - 1);
        $nodeArr                      = self::channelLevel($data, $v[$fieldPri], $node, $html, $fieldPri, $fieldPid, $level + 1);
        if (!empty($nodeArr)) $arr[$v[$fieldPri]][$node] = $nodeArr;
      }
    }
    $arr = Arr::resetKeys($arr);
    return $arr;
  }

  /**
   * 获得所有子栏目
   * @param array $data 栏目数据
   * @param int $pid 操作的栏目
   * @param string $html 栏目名前字符
   * @param string $fieldPri 表主键
   * @param string $fieldPid 父id
   * @param int $level 等级
   * @return array
   */
  static public function channelList($data, $pid = 0, $html = "&nbsp;", $fieldPri = 'id', $fieldPid = 'pid', $level = 1)
  {
    $data = self::_channelList($data, $pid, $html, $fieldPri, $fieldPid, $level);
    if (empty($data)) return $data;
    foreach ($data as $n => $m) {
      if ($m['_level'] == 1) continue;
      $data[$n]['_first'] = false;
      $data[$n]['_end']   = false;
      if (!isset($data[$n - 1]) || $data[$n - 1]['_level'] != $m['_level']) {
        $data[$n]['_first'] = true;
      }
      if (isset($data[$n + 1]) && $data[$n]['_level'] > $data[$n + 1]['_level']) {
        $data[$n]['_end'] = true;
      }
    }
    //更新key为栏目主键
    $category = array();
    foreach ($data as $d) {
      $category[$d[$fieldPri]] = $d;
    }
    return $category;
  }

  //只供channelList方法使用
  static private function _channelList($data, $pid = 0, $html = "&nbsp;", $fieldPri = 'id', $fieldPid = 'pid', $level = 1)
  {
    if (empty($data)) return [];
    $arr = [];
    foreach ($data as $v) {
      $id = $v[$fieldPri];
      if ($v[$fieldPid] == $pid) {
        $v['_level'] = $level;
        $v['_html']  = str_repeat($html, $level - 1);
        $v['_path']  = $v['id'];
        array_push($arr, $v);
        $tmp = self::_channelList($data, $id, $html, $fieldPri, $fieldPid, $level + 1);
        $arr = array_merge($arr, $tmp);
      }
    }
    return $arr;
  }

  /**
   * 获得树状数据
   * @param array $data 数据
   * @param string $title 字段名
   * @param string $fieldPri 主键id
   * @param string $fieldPid 父id
   * @return array
   */
  static public function tree($data, $title, $fieldPri = 'id', $fieldPid = 'pid')
  {
    if (!is_array($data) || empty($data)) return [];
    $arr = self::channelList($data, 0, '', $fieldPri, $fieldPid);
    foreach ($arr as $k => $v) {
      $str = "";
      if ($v['_level'] > 2) {
        for ($i = 1; $i < $v['_level'] - 1; $i++) {
          $str .= "&nbsp;&nbsp;&nbsp;&nbsp;";
        }
      }
      if ($v['_level'] != 1) {
        $t = $title ? $v[$title] : "";
        if ($arr[$k]['_end'] == 1) {
          $arr[$k]['_name'] = $str . "└─ " . $v['_html'] . $t;
        } else {
          $arr[$k]['_name'] = $str . "├─ " . $v['_html'] . $t;
        }
      } else {
        $arr[$k]['_name'] = $v[$title];
      }
    }
    //设置主键为$fieldPri
    $data = array();
    foreach ($arr as $d) {
      $data[$d[$fieldPri]] = $d;
    }
    return $data;
  }

  /**
   * 获得所有父级栏目
   * @param $data //栏目数据
   * @param $sid //子栏目
   * @param string $fieldPri 唯一键名，如果是表则是表的主键
   * @param string $fieldPid 父ID键名
   * @return array
   */
  static public function parentChannel($data, $sid, $fieldPri = 'id', $fieldPid = 'pid')
  {
    if (empty($data)) return [];
    $arr = array();
    foreach ($data as $v) {
      if ($v[$fieldPri] == $sid) {
        $arr[] = $v;
        $_n    = self::parentChannel($data, $v[$fieldPid], $fieldPri, $fieldPid);
        if (!empty($_n)) {
          $arr = array_merge($arr, $_n);
        }
      }
    }
    return $arr;
  }

  /**
   * 判断$s_cid是否是$d_cid的子栏目
   * @param $data //栏目数据
   * @param $sid //子栏目id
   * @param $pid //父栏目id
   * @param string $fieldPri 主键
   * @param string $fieldPid 父id字段
   * @return bool
   */
  static function isChild($data, $sid, $pid, $fieldPri = 'id', $fieldPid = 'pid')
  {
    $_data = self::channelList($data, $pid, '', $fieldPri, $fieldPid);
    foreach ($_data as $c) {
      //目标栏目为源栏目的子栏目
      if ($c[$fieldPri] == $sid)
        return true;
    }
    return false;
  }

  /**
   * 检测是否有子栏目
   * @param $data //栏目数据
   * @param $cid //要判断的栏目cid
   * @param string $fieldPid 父id表字段名
   * @return bool
   */
  static function hasChild($data, $cid, $fieldPid = 'pid')
  {
    foreach ($data as $d) {
      if ($d[$fieldPid] == $cid) return true;
    }
    return false;
  }
}
